package cn.maihe.elg.operation.centers.fuzhou.auth;

import cn.maihe.elg.operation.centers.fuzhou.auth.utils.SM2Util;
import cn.maihe.elg.operation.centers.fuzhou.config.FZMakeInfoConfig;
import cn.maihe.elg.operation.common.auth.Encryption;
import cn.maihe.elg.operation.config.ElgAuthConfig;
import cn.maihe.elg.operation.supports.bank.cmb.util.DcHelper;
import cn.maihe.elg.operation.utils.RsaUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * @Description 海迈中心 加解密算法sm2 公钥加密 私钥解密
 * @Author WJH
 * @Date 2021/07/12
 */
@Slf4j
public class FZEncryption implements Encryption {

    private String sm2PubKey;
    private String sm2PriKey;
    private String apiRsaPk;

    public FZEncryption(ElgAuthConfig elgAuthConfig, FZMakeInfoConfig.CenterInfo centerInfo) {

        Assert.hasText(centerInfo.getSm2PubKey(), () -> centerInfo.getSysName() + "的金融机构sm2PubKey未配置");
        Assert.hasText(centerInfo.getSm2PriKey(), () -> centerInfo.getSysName() + "的金融机构sm2PriKey未配置");
        Assert.hasText(centerInfo.getApiRsaPk(), () -> centerInfo.getSysName() + "的公用RSA公钥[api_rsa_pk]未配置");

        this.sm2PriKey = centerInfo.getSm2PriKey();
        this.sm2PubKey = centerInfo.getSm2PubKey();
        this.apiRsaPk = centerInfo.getApiRsaPk();
    }


    /**
     * SM2 公钥加密
     *
     * @param unEncryptedData
     * @return
     */
    @Override
    public byte[] encrypt(byte[] unEncryptedData) {
        return encrypt(new String(unEncryptedData, StandardCharsets.UTF_8)).getBytes(StandardCharsets.UTF_8);
    }

    /**
     * RSA公钥加密
     *
     * @param clearBizReqBody 明文
     * @return
     */
    public String encrypt(String clearBizReqBody) {
        Assert.hasText(clearBizReqBody, () -> "待加密数据不能为空");
        JSONObject requestJson = JSON.parseObject(clearBizReqBody, JSONObject.class);
//        JsonObject requestJson = new Gson().fromJson(clearBizReqBody, JsonObject.class);
        String method = String.valueOf(requestJson.get("method"));
//        requestJson.remove("access_token");
        clearBizReqBody = JSONSort(requestJson);
//        Assert.hasText(accessToken, () -> "待加密数据access_token不能为空");
//        clearBizReqBody = JSON.toJSONString(requestJson);
//        clearBizReqBody = JSON.toJSONString(requestJson);
        try {
//            byte[] publicKeyBytes = Base64.getDecoder().decode(sm2PubKey);
//            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(publicKeyBytes);
//            PublicKey publicKey = java.security.KeyFactory.getInstance("RSA").generatePublic(keySpec);
////            String ciphertext = URLDecoder.decode(clearBizReqBody, "UTF-8");
//            String ciphertext = URLEncoder.encode(clearBizReqBody, "UTF-8");
//            byte[] encryptedBytes = Base64.getDecoder().decode(ciphertext);
//            return new String(RsaUtil.encryptByPublicKey(encryptedBytes,publicKey));
            if ("get_access_token".equals(method)) {
                return RsaUtil.encryptSegment(clearBizReqBody, apiRsaPk);
//                return RsaUtil.encryptByPublicKey(clearBizReqBody, apiRsaPk);
            }
            return RsaUtil.encryptSegment(clearBizReqBody, sm2PubKey);
//            return RsaUtil.encryptByPublicKey(clearBizReqBody, sm2PubKey);
//            return SM2Util.encrypt(sm2PubKey, clearBizReqBody);
        } catch (Exception e) {
            throw new RuntimeException("加密异常:" + e.getMessage(), e);
        }
    }


    /**
     * sm2 私钥解密
     *
     * @param encryptedData
     * @return
     */
    @Override
    public byte[] decrypt(byte[] encryptedData) {
        return decrypt(new String(encryptedData, StandardCharsets.UTF_8)).getBytes(StandardCharsets.UTF_8);
    }

    /**
     * RSA私钥解密
     *
     * @param encryptAndB64ReqBody 密文
     * @return
     */
    public String decrypt(String encryptAndB64ReqBody) {
        Assert.hasText(encryptAndB64ReqBody, () -> "待解密数据不能为空");
        try {
            return RsaUtil.decryptSegment(encryptAndB64ReqBody, sm2PriKey);
//            return SM2Util.decrypt(sm2PriKey, encryptAndB64ReqBody);
        } catch (Exception e) {
            throw new RuntimeException("解密失败:" + e.getMessage(), e);
        }
    }

    /**
     * 把所有参数名和参数值串在一起, 排除access_token字段
     *
     * @param json
     * @return
     */
    private static String JSONSort(JSONObject json) {
        // 将JSON对象的键存入TreeMap
        TreeMap<String, Object> sortedMap = new TreeMap<>();
        for (String key : json.keySet()) {
            if (!("access_token").equals(key)) {
                sortedMap.put(key, json.get(key));
            }
        }
        // 创建排序后的JSON对象
        JSONObject sortedJsonObject = new JSONObject(sortedMap);
        return JSONObject.toJSONString(sortedJsonObject);
    }

}
